package com.piece.core.web.util;

import com.piece.core.framework.constant.ApplicationConstants;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.util.file.FreemarkerUtil;
import com.piece.core.framework.util.basic.SpringUtil;
import com.piece.core.framework.properties.ApplicationProperties;
import com.piece.core.log.client.LogFactory;
import com.piece.core.log.client.dto.MessageLogDTO;
import com.piece.core.log.enums.MessageLogType;
import com.piece.core.log.support.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 邮件发送工具
 */
@Slf4j
public class MailUtil {

    private static final ReentrantLock lock = new ReentrantLock();
    private String applicationName;
    private LogFactory auditLogFactory;

    private String from;
    private JavaMailSender javaMailSender;
    private static MailUtil instance;

    public static MailUtil getInstance() {
        if (null == instance) {
            lock.lock();
            if (null == instance) {
                instance = new MailUtil();
                ApplicationProperties properties = SpringUtil.getBean(ApplicationProperties.class);
                instance.applicationName = properties.getValue(ApplicationConstants.APPLICATION_ID);
                instance.from = properties.getValue(ApplicationConstants.MAIL_FROM);
                instance.setJavaMailSender(initProp(properties));

                LogFactory auditLogFactory = SpringUtil.getBean(LogFactory.class);
                instance.setAuditLogFactory(auditLogFactory);
            }
            lock.unlock();
        }
        return instance;
    }

    /**
     * 更新邮箱配置信息
     */
    public static MailUtil updateInstance() {
        MailUtil instance = getInstance();
        ApplicationProperties properties = SpringUtil.getBean(ApplicationProperties.class);
        instance.from = properties.getValue(ApplicationConstants.MAIL_FROM);
        instance.setJavaMailSender(initProp(properties));
        return instance;
    }

    private static JavaMailSenderImpl initProp(ApplicationProperties properties) {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(properties.getValue(ApplicationConstants.MAIL_HOST));
        mailSender.setPort(25);
        mailSender.setUsername(properties.getValue(ApplicationConstants.MAIL_FROM));
        mailSender.setPassword(properties.getValue(ApplicationConstants.MAIL_PASSWORD));
        return mailSender;
    }

    /**
     * 发送文本邮件
     *
     * @param to      发送地址
     * @param subject 主题
     * @param content 内容
     */
    public boolean sendSimpleMail(String to, String subject, String content) {
        return sendSimpleMail(to, null, subject, content);
    }

    /**
     * 发送文本邮件
     *
     * @param to      发送地址
     * @param cc      抄送地址
     * @param subject 主题
     * @param content 内容
     */
    public boolean sendSimpleMail(String to, String[] cc, String subject, String content) {
        MessageLogDTO messageLog = recordLog(to, subject, content);
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage.setFrom(from);
            simpleMailMessage.setTo(to);
            if (null != cc) {
                simpleMailMessage.setCc(cc);
            }
            simpleMailMessage.setSubject(subject);
            simpleMailMessage.setText(content);
            javaMailSender.send(simpleMailMessage);
            return true;
        } catch (MailException e) {
            log.error("向{}发送邮件异常", to,e);

            messageLog.setStatus(StatusType.FAIL.getCode());
            messageLog.setDesc(e.getMessage());
            return false;
        } finally {
            saveLog(messageLog);
        }
    }

    /**
     * 发送html格式邮件
     *
     * @param to      发送地址
     * @param subject 主题
     * @param html    内容
     */
    public boolean sendHtmlMail(String to, String subject, String html) {
        return sendHtmlMail(to, null, subject, html);
    }

    /**
     * 发送html格式邮件
     *
     * @param to      发送地址
     * @param cc      抄送地址
     * @param subject 主题
     * @param html    内容
     */
    public boolean sendHtmlMail(String to, String[] cc, String subject, String html) {
        MessageLogDTO messageLog = recordLog(to, subject, html);
        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
            helper.setFrom(from);
            helper.setTo(to);
            if (null != cc) {
                helper.setCc(cc);
            }
            helper.setSubject(subject);
            helper.setText(html, true);
            javaMailSender.send(message);
            return true;
        } catch (Exception e) {
            log.error("向{}发送邮件异常", to, e);

            messageLog.setStatus(StatusType.FAIL.getCode());
            messageLog.setDesc(e.getMessage());
            return false;
        } finally {
            saveLog(messageLog);
        }
    }

    /**
     * 发送带附件邮件
     *
     * @param to                 发送地址
     * @param subject            主题
     * @param html               内容
     * @param attachNames        附件名称
     * @param inputStreamSources 附件流
     */
    public boolean sendAttachmentsMail(String to, String subject, String html, List<String> attachNames, List<InputStreamSource> inputStreamSources) {
        return sendAttachmentsMail(to, null, subject, html, attachNames, inputStreamSources);
    }

    /**
     * 发送带附件邮件
     *
     * @param to                 发送地址
     * @param subject            主题
     * @param html               内容
     * @param attachNames        附件名称
     * @param inputStreamSources 附件流
     */
    public boolean sendAttachmentsMail(String to, String[] cc, String subject, String html, List<String> attachNames, List<InputStreamSource> inputStreamSources) {
        MessageLogDTO messageLog = recordLog(to, subject, html);
        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
            helper.setFrom(from);
            helper.setTo(to);
            if (null != cc) {
                helper.setCc(cc);
            }
            helper.setSubject(subject);
            helper.setText(html, true);
            if (attachNames != null && attachNames.size() > 0 && attachNames.size() == inputStreamSources.size()) {
                for (int i = 0; i < attachNames.size(); i++) {
                    helper.addAttachment(attachNames.get(i), inputStreamSources.get(i));
                }
            }
            javaMailSender.send(message);
            return true;
        } catch (Exception e) {
            log.error("向{}发送邮件异常", to, e);

            messageLog.setStatus(StatusType.FAIL.getCode());
            messageLog.setDesc(e.getMessage());
            return false;
        } finally {
            saveLog(messageLog);
        }
    }

    /**
     * 发送模板邮件
     *
     * @param to           发送地址
     * @param subject      主题
     * @param templatePath ftl模板路径
     * @param templateName ftl模板名称
     * @param dataModel    对象模型
     */
    public boolean sendMail(String to, String subject, String templatePath, String templateName, Object dataModel) {
        return sendMail(to, null, subject, templatePath, templateName, dataModel);
    }

    /**
     * 发送模板邮件
     *
     * @param to           发送地址
     * @param subject      主题
     * @param templatePath ftl模板路径
     * @param templateName ftl模板名称
     * @param dataModel    对象模型
     */
    public boolean sendMail(String to, String[] cc, String subject, String templatePath, String templateName, Object dataModel) {
        MessageLogDTO messageLog = recordLog(to, subject, templatePath + File.separator + templateName);
        try {
            //获取模板信息
            String html = FreemarkerUtil.generateHtmlByFreemarker(templatePath, templateName, dataModel);
            messageLog.setContent(html);

            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
            helper.setFrom(from);
            helper.setTo(to);
            if (null != cc) {
                helper.setCc(cc);
            }
            helper.setSubject(subject);

            helper.setText(html, true);
            javaMailSender.send(message);
            return true;
        } catch (Exception e) {
            log.error("向{}发送邮件异常", to, e);

            messageLog.setStatus(StatusType.FAIL.getCode());
            messageLog.setDesc(e.getMessage());
            return false;
        } finally {
            saveLog(messageLog);
        }
    }

    private MessageLogDTO recordLog(String email, String subject, String content) {
        MessageLogDTO messageLog = LogUtil.buildMessageLog(applicationName);
        messageLog.setType(MessageLogType.MAIL.getType().toString());
        messageLog.setAddress(email);
        messageLog.setTitle(subject);
        messageLog.setContent(content);
        return messageLog;
    }

    private MessageLogDTO saveLog(MessageLogDTO log) {
        if (null != auditLogFactory.getMessageLog())
            log = auditLogFactory.getMessageLog().save(log);

        return log;
    }

    public void setJavaMailSender(JavaMailSender javaMailSender) {
        this.javaMailSender = javaMailSender;
    }

    public void setAuditLogFactory(LogFactory auditLogFactory) {
        this.auditLogFactory = auditLogFactory;
    }
}
